package eth

import (
	"fmt"
	"net"

	"gitee.com/liumou_site/logger"
)

// GetEthListInfo 获取所有网卡的信息
// 该函数通过调用 GetEthList 和 GetEthInfo 方法获取所有网卡的信息。
// 通过 Info 字段记录所有网卡的信息。
func (e *Eth) GetEthListInfo() {
	// 获取本机所有网络接口的名称列表
	ethList := e.GetEthList()
	if len(ethList) == 0 {
		logger.Error("GetEthListInfo: 本机无网络接口")
		e.Err = fmt.Errorf("本机无网络接口")
		return
	}

	// 遍历每个网络接口进行详细信息获取
	for _, eth := range ethList {
		// 获取指定网卡的详细信息（IP地址、MAC地址、子网掩码等）
		ethInfo, err := e.GetEthInfo(eth)

		// 错误处理：当获取单网卡信息失败时
		if err != nil {
			// 记录错误日志，包含具体的错误信息
			logger.Error("GetEthListInfo: 获取网卡信息失败", err)

			// 在结构体中存储错误信息供调用方检查
			e.Err = fmt.Errorf("获取网卡[%s]信息失败: %v", eth, err)

			// 遇到错误立即终止处理流程
			return
		}

		// 将成功获取的网卡信息追加到结构体的信息集合中
		// 使用指针解引用追加结构体副本，避免内存引用问题
		e.Info = append(e.Info, *ethInfo)
	}
}

// GetEthInfoV4 获取指定网卡的IPv4信息。
// 参数:
//
//	eth string - 网卡名称。
//
// 返回值:
//
//	*Info - 包含网卡信息的结构体指针。
//	error - 如果发生错误，则返回错误信息，否则返回nil
func (e *Eth) GetEthInfoV4(eth string) (*Info, error) {
	// 初始化一个Info切片来存储结果。
	var res *Info
	// 初始化一个IP切片来存储IPv4地址。
	var ips []net.IP
	// 初始化一个IpInfo切片来存储处理后的IP信息。
	var infos []IpInfo

	// 调用GetEthInfo方法获取指定网卡的信息。
	info, err := e.GetEthInfo(eth)
	// 如果发生错误，直接返回nil和错误信息。
	if err != nil {
		return nil, err
	}
	// 将获取到的信息赋值给结果变量。
	res = info

	// 遍历网卡的IP信息，寻找IPv4地址。
	for _, ip := range info.Ip {
		logger.Debug(ip)
		// 如果找到IPv4地址，将网卡信息添加到结果切片中。
		if ip.Ip.To4() != nil {
			ips = append(ips, ip.Ip)
		}
	}

	// 如果没有找到IPv4地址，返回自定义的错误信息。
	if len(ips) == 0 {
		return nil, fmt.Errorf("网卡[%s]无IPv4地址", eth)
	}
	// 清空原始IP信息列表，重新构建IPv4专用信息
	infos = []IpInfo{}

	// 遍历IPv4地址，构造并添加IpInfo到结果切片中。
	for i, ip_ := range ips {
		var ipInfo IpInfo
		ipInfo.Ip = ip_

		// 查找对应IP在原始列表中的掩码信息
		for _, origIp := range info.Ip {
			if origIp.Ip.Equal(ip_) {
				// 确保使用IPv4掩码长度，最大为32
				if origIp.MaskInt > 32 {
					ipInfo.MaskInt = 32 // 设置默认值为32，表示255.255.255.255
				} else if origIp.MaskInt <= 0 {
					ipInfo.MaskInt = 24 // 设置一个常见默认值24，表示255.255.255.0
				} else {
					ipInfo.MaskInt = origIp.MaskInt
				}

				// 确保掩码对象存在
				if origIp.Mask != nil {
					ipInfo.Mask = origIp.Mask
				} else if ipInfo.MaskInt > 0 {
					// 如果有掩码长度但无掩码对象，则创建一个
					mask := net.CIDRMask(ipInfo.MaskInt, 32)
					ipInfo.Mask = net.IP(mask)
				}
				// 新增：赋值网关
				gw, _ := e.GetGateway(eth, ip_)
				if gw != nil {
					ipInfo.Gw = gw.IP
				}
				break
			}
		}

		// 如果没有找到匹配的掩码信息，使用合理的默认值
		if ipInfo.MaskInt == 0 {
			ipInfo.MaskInt = 24 // 默认子网掩码255.255.255.0
			mask := net.CIDRMask(ipInfo.MaskInt, 32)
			ipInfo.Mask = net.IP(mask)
		}

		infos = append(infos, ipInfo)

		// 如果是第一个IP且主结构体没有掩码，则设置主掩码
		if i == 0 && res.Mask == nil {
			res.Mask = ipInfo.Mask
		}
	}

	// 更新结果的IP信息为处理后的IPv4信息。
	res.Ip = infos
	res.Version = 4

	// 返回结果切片和nil错误，表示操作成功。
	return res, nil
}

// GetEthInfo 获取指定网卡的网卡信息
func (e *Eth) GetEthInfo(eth string) (*Info, error) {
	// 获取指定网卡的详细信息
	inter, err := net.InterfaceByName(eth)
	if err != nil {
		logger.Error("GetEthInfo: 获取网卡信息失败", err)
		return nil, fmt.Errorf("获取网卡信息失败: %v", err)
	}

	// 获取指定网卡的IP地址
	adders, err := inter.Addrs()
	if err != nil {
		logger.Error("GetEthInfo: 获取IP地址失败", err)
		return nil, fmt.Errorf("获取IP地址失败: %v", err)
	}
	// 初始化EthInfo结构体
	ethInfo := &Info{
		Name:    eth,
		Ip:      []IpInfo{},
		Ip6Info: []Ip6Info{},
		Mac:     inter.HardwareAddr.String(),
		Sub:     nil,
		Mask:    nil,
		DnsList: nil,
		Version: 4,
	}

	// 处理IP地址
	if len(adders) == 0 {
		logger.Warn("网卡无IP地址: ", eth)
		return ethInfo, nil
	}

	for _, addr := range adders {
		if ip, ok := addr.(*net.IPNet); ok && !ip.IP.IsLoopback() {
			if ip.IP.To4() != nil {
				var ipInfo IpInfo
				ipInfo.Ip = ip.IP
				// 掩码
				_, info, err := net.ParseCIDR(addr.String())
				if err == nil {
					mask := info.Mask
					maskStr := net.IP(mask).String()
					ipInfo.Mask = net.ParseIP(maskStr)
					ethInfo.Mask = net.ParseIP(maskStr)
				}
				// 掩码长度
				ipv4MaskInt, _ := ip.Mask.Size()
				ipInfo.MaskInt = ipv4MaskInt
				// 网关
				gw, _ := e.GetGateway(eth, ip.IP)
				if gw != nil {
					ipInfo.Gw = gw.IP
				}
				ethInfo.Ip = append(ethInfo.Ip, ipInfo)
				ethInfo.Sub = ip.IP.Mask(ip.Mask)
				ethInfo.DnsList, _ = e.GetEthDNS(eth)
			} else {
				// IPv6
				var ip6Info Ip6Info
				ip6Info.Ip = ip.IP
				ipv6MaskInt, _ := ip.Mask.Size()
				ip6Info.MaskInt = ipv6MaskInt
				ip6Info.Mask = net.IP(ip.Mask)
				// ScopeId
				// net.IP没有ZoneId字段，ScopeId暂不赋值
				ip6Info.ScopeId = 0
				gw6, _ := e.GetGateway(eth, ip.IP)
				if gw6 != nil {
					ip6Info.Gw = gw6.IP
				}
				ethInfo.Ip6Info = append(ethInfo.Ip6Info, ip6Info)
				ethInfo.Version = 6
			}
		}
	}
	return ethInfo, nil
}

// GetEthList 获取当前系统中所有正在使用的网络接口名称列表。
// 该函数通过查询系统中的网络接口信息，筛选出所有处于激活状态（即接口标志中包含FlagUp）的网络接口，
// 并将其名称添加到一个字符串列表中，最后返回该列表。
// 如果在获取网络接口信息时发生错误，函数将直接返回nil。
func (e *Eth) GetEthList() []string {
	// 获取系统中的所有网络接口信息。
	interfaces, err := net.Interfaces()
	if err != nil {
		// 如果发生错误，直接返回nil。
		return nil
	}

	// 初始化一个空的字符串切片，用于存储激活状态的网络接口名称。
	var ethList []string

	// 遍历所有网络接口信息。
	for _, inter := range interfaces {
		if inter.Name == "lo" || inter.Name == "docker0" {
			logger.Debug("Ignore loopback and Docker network card: ", inter.Name)
			continue
		}
		// 检查网络接口是否处于激活状态。
		if inter.Flags&net.FlagUp != 0 {
			// 如果是，将接口名称添加到列表中。
			if e.Debug {
				logger.Debug("Active network card: ", inter.Name)
			}
			ethList = append(ethList, inter.Name)
		} else {
			logger.Warn("Ignore inactive or virtual network cards: ", inter.Name)
		}
	}
	// 返回包含所有激活状态网络接口名称的列表。
	if len(ethList) == 0 {
		logger.Warn("No active network cards found.")
		return nil
	}
	return ethList
}
